package com.qf.air.search.service.impl;

import com.qf.air.search.enums.AirEnum;
import com.qf.air.search.exception.AirEx;
import com.qf.air.search.service.ElasticsearchService;
import com.qf.air.search.util.R;
import com.qf.air.search.vo.ResultVO;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 何星宇
 * @version V1.0
 * @Date 2021/11/8 11:29
 */

@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public ResultVO findAirIndex(Integer page, Integer rows, Integer districtId, String monitoringStation, Date startTime, Date endTime) {
        //创建指定的request
        SearchRequest request = new SearchRequest();
        request.indices("air_index");

        //封装查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //复合查询封装
        BoolQueryBuilder bool = QueryBuilders.boolQuery();

        //查询所有
        if (StringUtils.isEmpty(monitoringStation) && startTime == null && endTime == null) {
            MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
            bool.must(matchAllQuery);
        }

        //区域id
        if (districtId != null && districtId != 0) {
            MatchQueryBuilder districtIdBuilder = QueryBuilders.matchQuery("districtId", districtId);
            bool.must(districtIdBuilder);
        }
        //监测站
        if (!StringUtils.isEmpty(monitoringStation)) {
            MatchQueryBuilder msBuilder = QueryBuilders.matchQuery("monitoringStation", monitoringStation);
            bool.must(msBuilder);

            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.fragmentSize(monitoringStation.length());
            highlightBuilder.preTags("<span style='color:red;'>");
            highlightBuilder.postTags("</span>");
            highlightBuilder.field("monitoringStation");
            //高亮显示
            sourceBuilder.highlighter(highlightBuilder);
        }
        //起始结束时间
        if (startTime != null || endTime != null) {
            RangeQueryBuilder monitorTimeBuilder = QueryBuilders.rangeQuery("monitorTime");
            if (startTime != null) {
                monitorTimeBuilder.gte(startTime);
            }
            if (endTime != null) {
                monitorTimeBuilder.lte(endTime);
            }
            bool.must(monitorTimeBuilder);
        }

        //复合查询
        sourceBuilder.query(bool);
        //分页
        sourceBuilder.from((page - 1) * rows);
        sourceBuilder.size(rows);
        //排序
        sourceBuilder.sort("_id", SortOrder.DESC);

        //封装到request
        request.source(sourceBuilder);

        //发送请求，得到响应
        SearchResponse response = null;
        try {
            response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //封装数据
        List result = new ArrayList();
        for (SearchHit hit : response.getHits().getHits()) {
            Map<String, Object> map = hit.getSourceAsMap();
            HighlightField highlightField = hit.getHighlightFields().get("monitoringStation");
            if (highlightField != null) {
                String value = highlightField.getFragments()[0].toString();
                map.put("monitoringStation", value);
            }
            result.add(map);
        }

        //封装数据
        return R.ok(result, response.getHits().getTotalHits().value);
    }

    @Override
    public void add(Map map) throws IOException {
        //创建request
        IndexRequest request = new IndexRequest();
        request.index("air_index");
        request.id(map.get("id").toString());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        request.source(map);

        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        if(!response.getResult().toString().equalsIgnoreCase("CREATED")){
            System.out.println("添加信息失败！ air=" + map);
            throw new AirEx(AirEnum.AIR_ADD_ERROR);
        }

    }

    @Override
    public List<Map> echarts() throws IOException {
        SearchRequest request = new SearchRequest();
        request.indices("air_index");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        TermsAggregationBuilder termsAggregationBuilder = new TermsAggregationBuilder("Terms");
        termsAggregationBuilder.field("districtName.keyword");
        termsAggregationBuilder.size(5);
        SearchSourceBuilder searchSourceBuilder = sourceBuilder.aggregation(termsAggregationBuilder);
        request.source(searchSourceBuilder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        Terms terms = response.getAggregations().get("Terms");
        List<Map> result = new ArrayList<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            Map map = new HashMap();
            map.put("name", bucket.getKey());
            map.put("value", bucket.getDocCount());
            result.add(map);
        }
        return result;
    }
}
